package socket;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 聊天室服务端
 */
public class Server {

    ///private List<PrintWriter> allOut = new ArrayList<>();//供内部类访问

    private ServerSocket serverSocket;

    private Map<String, PrintWriter> allOut = new HashMap<>();

    /**
     * 构造方法：初始化操作
     */
    public Server() {
        try {
            System.out.println("正在启动服务端……");
            serverSocket = new ServerSocket(8089);
            System.out.println("服务端启动完毕！！！");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * start方法
     */
    public void start() {
        try {
            while (true) {
                System.out.println("等待客户端连接……");
                Socket socket = serverSocket.accept();//阻塞方法
                System.out.println("一个客户端连接成功！！！");

                //启动一个线程来处理与客户端的交互
                ClientHandler handler = new ClientHandler(socket);
                Thread t = new Thread(handler);
                t.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * main方法
     */
    public static void main(String[] args) {
        Server server = new Server();
        server.start();
    }

    //线程
    private class ClientHandler implements Runnable {
        private Socket socket;
        private String host;//记录IP
        private String nickname;//记录昵称

        public ClientHandler(Socket socket) {
            this.socket = socket;
            host = socket.getInetAddress().getHostAddress();
        }

        PrintWriter pw = null;

        public void run() {
            try {
                InputStream in = socket.getInputStream();
                InputStreamReader isr = new InputStreamReader(in, StandardCharsets.UTF_8);
                BufferedReader br = new BufferedReader(isr);

                //单独读取第一行昵称
                nickname = br.readLine();

                OutputStream out = socket.getOutputStream();
                OutputStreamWriter osw = new OutputStreamWriter(out, StandardCharsets.UTF_8);
                BufferedWriter bw = new BufferedWriter(osw);
                pw = new PrintWriter(bw, true);
                //将该输出流存入allOut集合中
                synchronized (allOut) {
                    //allOut.add(pw);
                    int num = 1;
                    String newNickname = nickname;
                    while (true) {
                        if (allOut.containsKey(newNickname)) {
                            newNickname = nickname + num;
                            num++;
                        } else {
                            allOut.put(newNickname, pw);
                            nickname = newNickname;
                            break;
                        }
                    }
                }
                //广播
                sendMessage(nickname + "上线了，当前在线人数：" + allOut.size());

                String message;
                while ((message = br.readLine()) != null) {
                    if (message.startsWith("@")) {
                        sendMessageToSomeOne(message);
                    } else {
                        sendMessage(nickname + "[" + host + "]说：" + message);
                        saveMessage(nickname,null,message);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //客户端断开
                synchronized (allOut) {
                    allOut.remove(nickname);
                }
                sendMessage(nickname + "下线了，当前在线人数：" + allOut.size());
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        public void sendMessage(String message) {
            System.out.println(message);
            synchronized (allOut) {
                for (PrintWriter o : allOut.values()) {
                    o.println(message);
                }
            }
        }

        private void sendMessageToSomeOne(String message) {
            if (message.matches("@.+:.+")) {
                String toNickName = message.substring(1, message.indexOf(":"));
                if (allOut.containsKey(toNickName)) {
                    PrintWriter pw = allOut.get(toNickName);
                    message = message.substring(message.indexOf(":") + 1);
                    String toMessage = nickname + "悄悄对你说：" + message;
                    pw.println(toMessage);
                    saveMessage(nickname,toNickName,message);
                } else {
                    PrintWriter pw = allOut.get(nickname);
                    pw.println(toNickName + "不在线");
                }
            } else {
                PrintWriter pw = allOut.get(nickname);
                pw.println("私聊格式不正确，正确格式：@对方昵称:消息内容");
            }
        }

        private void saveMessage(String fromUser, String toUser, String message){
            try(Connection conn = DBUtil.getConnection()){
                String sql = "INSERT INTO chatinfo "+
                             "(fromUser,toUser,message) VALUES(?,?,?)";

                PreparedStatement ps = conn.prepareStatement(sql);
                ps.setString(1,fromUser);
                ps.setString(2,toUser);
                ps.setString(3,message);
                ps.executeUpdate();
            }catch(SQLException e){
                e.printStackTrace();
            }
        }
    }
}
